package com.wsg.dep.seq;

import com.wsg.dep.util.UnSafeUtil;
import sun.misc.Unsafe;

/**
 * 高性能序列号生成器，优化点：
 * 1. 消除伪共享（@Contended + 缓存行填充）
 * 2. 无锁原子操作（CAS + Unsafe指令级优化）
 * 3. 批量操作支持（减少CAS次数）
 */
public class Sequence extends RhsPadding {

    /**
     * 初始化值
     */
    public static final long INITIAL_VALUE = -1L;

    /**
     * 不安全的低级别操作
     */
    private static final Unsafe UNSAFE;

    /**
     * value在对象内存中的相对偏移位置
     */
    private static final long VALUE_OFFSET;

    static {
        UNSAFE = UnSafeUtil.getUnsafe();
        try {
            // 获取Value对象中value属性字在内存中的偏移位置
            VALUE_OFFSET = UNSAFE.objectFieldOffset(Value.class.getDeclaredField("value"));
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 初始化value的值默认为-1
     */
    public Sequence()
    {
        this(INITIAL_VALUE);
    }

    /**
     * 使用传入的值初始化value的初始值
     *
     * @param initialValue 初始化值
     */
    public Sequence(final long initialValue)
    {
        // 将initialValue的值写入VALUE_OFFSET偏移位置
        UNSAFE.putOrderedLong(this, VALUE_OFFSET, initialValue);
    }




    /**
     * 获取序列号的值，即value的值
     *
     * @return 当前序列号的值
     */
    public long get()
    {
        return value;
    }

    /**
     * 指定一个序列号，并将VALUE_OFFSET偏移所在位置的值修改成指定的序列号
     * 不保证其他线程的可见性
     * 性能略优于putLongVolatile
     *
     * @param value 序列号的新值
     */
    public void set(final long value)
    {
        UNSAFE.putOrderedLong(this, VALUE_OFFSET, value);
    }

    /**
     * 指定一个序列号，并将VALUE_OFFSET偏移所在位置的值修改成指定的序列号，写入时保持volatile的特性
     * 保证其他线程的可见性
     * 性能略低于putOrderedLong
     *
     * @param value 序列号的新值
     */
    public void setVolatile(final long value)
    {
        UNSAFE.putLongVolatile(this, VALUE_OFFSET, value);
    }

    /**
     * 将当前对象中存储的序列值与预期值expectedValue进行比较，
     * 如果二者相等，就将序列值更新为newValue，并返回true；
     * 若不相等，则不进行更新操作，直接返回false
     *
     * @param expectedValue 过期的值或旧值.
     * @param newValue 新值.
     * @return 相等返回：true，其他返回：false
     */
    public boolean compareAndSet(final long expectedValue, final long newValue)
    {
        return UNSAFE.compareAndSwapLong(this, VALUE_OFFSET, expectedValue, newValue);
    }

    /**
     * 当前序列号加1
     * @return
     */
    public long incrementAndGet()
    {
        return addAndGet(1L);
    }

    /**
     * 在当前的序列号上增长一个长度
     * @param increment 增长值
     * @return
     */
    public long addAndGet(final long increment)
    {
        long currentValue;
        long newValue;

        do
        {
            currentValue = get();
            newValue = currentValue + increment;
        }
        while (!compareAndSet(currentValue, newValue));

        return newValue;
    }



    @Override
    public String toString()
    {
        return Long.toString(get());
    }

    public static void main(String[] args) {
        Sequence sequence = new Sequence();
        System.out.println(sequence.get());
        System.out.println(sequence.incrementAndGet());
        System.out.println(sequence.incrementAndGet());
        System.out.println(sequence.get());

        Sequence sequence1 = new Sequence();
        System.out.println(sequence1.get());
        System.out.println(sequence1.incrementAndGet());
        System.out.println(sequence.get());
        System.out.println(sequence1.get());


//        System.out.println(UNSAFE.getLong(VALUE_OFFSET));
    }
}
